﻿using BUGCOME.Infrastructure;
using BUGCOME.Infrastructure.Helper;
using BUGCOME.Infrastructure.IPTools;
using BUGCOME.Model.Auth;
using BUGCOME.Model.Auth.dto;
using BUGCOME.Model.Logs;
using BUGCOME.Service.Auth.IServices;
using Mapster;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SignalR;
using System.Collections.Concurrent;
using System.Web;

namespace BUGCOME.Signalr.Api.Signalr
{
    /// <summary>SignalR消息中心</summary>
    [ApiExplorerSettings(GroupName = "signalr")]
    public class MessageHub : Hub
    {
        /// <summary>
        /// 在线客户端字典（连接ID-在线用户信息）
        /// </summary>
        public static readonly ConcurrentDictionary<string, OnlineUsers> OnlineClients = new();

        /// <summary>
        /// 在线用户字典（用户ID-在线用户信息）
        /// </summary>
        private static readonly ConcurrentDictionary<long, OnlineUsers> Users = new();

        // 用户基础服务
        private readonly IUserBaseService userBaseService;
       
        // 用户在线日志服务
        private readonly IUserOnlineLogService userOnlineLogService;

        /// <summary>
        /// 造函数，注入服务
        /// </summary>
        /// <param name="userBaseService"></param>
        /// <param name="userOnlineLogService"></param>
        public MessageHub(IUserBaseService userBaseService, IUserOnlineLogService userOnlineLogService)
        {
            this.userBaseService = userBaseService;
            this.userOnlineLogService = userOnlineLogService;
        }

        /// <summary>
        /// 客户端连接时触发
        /// </summary>
        public override async Task OnConnectedAsync()
        {
            try
            {
                var context = App.HttpContext;
                var name = context.GetName();
                var ip = context.GetClientUserIp();
                var device = context.GetClientInfo().ToString();
                var qs = HttpUtility.ParseQueryString(context.GetQueryString());
                var from = qs.Get("from") ?? "web";
                var clientId = qs.Get("clientId");
                long userId = context.GetUId();
                string uuid = $"{device}{userId}{ip}";

                // 未认证或已存在连接则返回
                if (!Context.User.Identity.IsAuthenticated || OnlineClients.ContainsKey(Context.ConnectionId))
                    return;

                var ipInfo = IpTool.Search(ip);
                var onlineUser = new OnlineUsers(Context.ConnectionId, name, userId, ip, device)
                {
                    Location = ipInfo?.City,
                    Uuid = uuid,
                    Platform = from,
                    ClientId = clientId ?? Context.ConnectionId
                };

                // 添加到在线客户端字典
                OnlineClients[Context.ConnectionId] = onlineUser;
                // 更新用户信息
                var userInfo = Users.GetOrAdd(userId, _ => new OnlineUsers { Userid = userId, Name = name, LoginTime = DateTime.Now });
                UpdateUserOnlineTime(userInfo);

                // 通知所有客户端在线人数更新
                await Clients.All.SendAsync(HubsConstant.OnlineNum, new { num = OnlineClients.Count, OnlineClients });
            }
            catch (Exception ex)
            {
                Log.WriteLine(ConsoleColor.Red, $"OnConnectedAsync Error: {ex.Message}");
            }
        }

        /// <summary>
        /// 客户端断开连接时触发
        /// </summary>
        /// <param name="exception"></param>
        /// <returns></returns>
        public override async Task OnDisconnectedAsync(Exception? exception)
        {
            // 移除在线客户端
            if (OnlineClients.TryRemove(Context.ConnectionId, out var user))
            {
                if (Users.TryGetValue(user.Userid, out var userInfo))
                {
                    // 更新在线时长并记录日志
                    userInfo.TodayOnlineTime += user.OnlineTime;
                    await userOnlineLogService.AddUserOnlineLogAsync(new UserOnlineLog { TodayOnlineTime = Math.Round(userInfo.TodayOnlineTime, 2) }, user);
                }
                // 通知所有客户端在线人数更新
                await Clients.All.SendAsync(HubsConstant.OnlineNum, new { num = OnlineClients.Count, OnlineClients, leaveUser = user });
            }
        }

        /// <summary>
        /// 发送消息给指定用户
        /// </summary>
        [HubMethodName("sendMessage")]
        public async Task SendMessage(long toUserId, string message)
        {
            try
            {
                var userName = App.HttpContext.GetName();
                long userId = App.HttpContext.GetUId();
                var fromUser = await userBaseService.GetByIdAsync(userId);
                // 获取目标用户的所有连接
                var toUserConnections = OnlineClients.Values.Where(u => u.Userid == toUserId).Select(u => u.ConnnectionId).ToList();
                toUserConnections.Add(Context.ConnectionId);

                // 构建消息DTO
                ChatMessageDto messageDto = new()
                {
                    MsgType = 0,
                    StoredKey = $"{userId}-{toUserId}",
                    UserId = userId,
                    ChatId = Guid.NewGuid().ToString(),
                    ToUserId = toUserId,
                    Message = message,
                    Online = toUserConnections.Count > 1 ? 1 : 0,
                    ChatTime = DateTimeHelper.GetUnixTimeSeconds(DateTime.Now),
                    FromUser = fromUser.Adapt<ChatUserDto>()
                };

                // 离线则存储消息，在线则直接发送
                if (messageDto.Online == 0)
                {
                    await StoreOfflineMessage(messageDto);
                }
                else
                {
                    await Clients.Clients(toUserConnections).SendAsync("receiveChat", messageDto);
                }
            }
            catch (Exception ex)
            {
                Log.WriteLine(ConsoleColor.Red, $"SendMessage Error: {ex.Message}");
            }
        }

      
        /// <summary>
        /// 获取当前连接ID
        /// </summary>
        [HubMethodName("getConnId")]
        public string GetConnectId() => Context.ConnectionId;

        /// <summary>
        /// 处理登出，支持单设备登录
        /// </summary>
        [HubMethodName("logOut")]
        public async Task LogOut()
        {
            var singleLogin = AppSettings.Get<bool>("singleLogin");
            long userId = App.HttpContext.GetUId();
            if (singleLogin)
            {
                // 获取同用户其他连接并通知登出
                var connections = OnlineClients.Values.Where(u => u.Userid == userId && u.ConnnectionId != Context.ConnectionId).Select(u => u.ConnnectionId).ToList();
                await Clients.Clients(connections).SendAsync("logOut");
            }
        }

        #region 私有方法

        /// <summary>
        /// 存储离线消息
        /// </summary>
        /// <param name="message"></param>
        /// <returns></returns>
        private Task StoreOfflineMessage(ChatMessageDto message)
        {
            Console.WriteLine($"Storing offline message for {message.ToUserId}");
            return Task.CompletedTask;
        }


        /// <summary>
        /// 更新用户在线时间
        /// </summary>
        /// <param name="userInfo"></param>
        private void UpdateUserOnlineTime(OnlineUsers userInfo)
        {
            if (userInfo.LoginTime <= DateTime.Today)
            {
                userInfo.LoginTime = DateTime.Now;
                userInfo.TodayOnlineTime = 0;
            }
        }

        #endregion
    }
}